using System;
using System.Data;

namespace FreeFlow.Administration
{
	/// <summary>
	/// A procedure in the database.
	/// </summary>
	public class Procedure : DatabaseAware, IRefreshable, IDeletable
	{
    /// <summary>
    /// Creates a new <see cref="Procedure"/> instance.
    /// </summary>
    /// <param name="server">Server.</param>
    /// <param name="reader">The data reader.</param>
    internal Procedure(Server server, IDataReader reader) : base(server)
    {
      name = reader["eProcedureName"].ToString();
      lastPublished = (DateTime)reader["eLoadedTime"];
    }

    private string name;
    /// <summary>
    /// Gets the name of the procedure.
    /// </summary>
    public string Name
    {
      get
      {
        return name;
      }
    }

    private DateTime lastPublished;
    /// <summary>
    /// Gets the date and time the procedure was last published.
    /// </summary>
    public DateTime LastPublished
    {
      get
      {
        return lastPublished;
      }
    }

    private FormCollection forms;
    /// <summary>
    /// Gets the forms for this procedure.
    /// </summary>
    public FormCollection Forms
    {
      get
      {
        if (forms == null)
          forms = new FormCollection(Server, Name);
        return forms;
      }
    }

    private RoleCollection roles;
    /// <summary>
    /// Gets the non-dynamic roles for this procedure.
    /// </summary>
    public RoleCollection Roles
    {
      get
      {
        if (roles == null)
          roles = new RoleCollection(Server, Name);
        return roles;
      }
    }

    private MapCollection maps;
    /// <summary>
    /// Gets the maps in this procedure.
    /// </summary>
    /// <value>The maps.</value>
    public MapCollection Maps
    {
      get
      {
        if (maps == null)
          maps = new MapCollection(Server, Name);
        return maps;
      }
    }

    private ProcedureVersionCollection versions;
    /// <summary>
    /// Gets the versions of the procedure published to this database.
    /// </summary>
    public ProcedureVersionCollection Versions
    {
      get
      {
        if (versions == null)
          versions = new ProcedureVersionCollection(Server, Name);
        return versions;
      }
    }

    private DesignerLog designerLog;
    /// <summary>
    /// Gets the designer log entries for this procedure.
    /// </summary>
    public DesignerLog DesignerLog
    {
      get
      {
        if (designerLog == null)
          designerLog = new DesignerLog(Server, this);
        return designerLog;
      }
    }

    private AttachmentCollection attachments;
    /// <summary>
    /// Gets the attachments used in this procedure.
    /// </summary>
    public AttachmentCollection Attachments
    {
      get
      {
        if (attachments == null)
          attachments = new AttachmentCollection(Server, AttachmentType.Procedure, name);
        return attachments;
      }
    }

    private ScriptCollection scripts;
    /// <summary>
    /// Gets the scripts for this procedure.
    /// </summary>
    public ScriptCollection Scripts
    {
      get
      {
        if (scripts == null)
          scripts = new ScriptCollection(Server, this);
        return scripts;
      }
    }

    #region IRefreshable Members

    /// <summary>
    /// Refreshes the instance.
    /// </summary>
    public void Refresh()
    {
      forms = null;
      roles = null;
      maps = null;
      versions = null;
      designerLog = null;
      attachments = null;
      scripts = null;
    }

    #endregion
    #region IDeletable Members

    /// <summary>
    /// Deletes this procedure from the database.
    /// </summary>
    public void Delete()
    {
      Refresh();
      int mapCount = Maps.Count;
      using (IDbTransaction transaction = Server.BeginTransaction())
      {
        // delete maps
        for (int i = 0; i < mapCount; i++)
        {
          Maps[i].Delete(transaction);
        }

        // delete procedure specific stuff
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eAssignment WHERE eRoleName IN (SELECT eRoleName FROM eRole WHERE " +
          "eProcedureName = '{0}' AND eRoleName <> 'everybody' AND eRoleName NOT IN " +
          "(SELECT e2.eRoleName FROM eRole e1, eRole e2 WHERE e1.eProcedureName <> '{0}' AND e1.eRoleName = e2.eRoleName))", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eMap WHERE eProcedureName = '{0}'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eForm WHERE eProcedureName = '{0}'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eField WHERE eProcedureName = '{0}'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eRole WHERE eProcedureName = '{0}'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eLog WHERE eProcedureName = '{0}'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eAttachment WHERE eKey LIKE '3\t{0}\t%'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eStart WHERE eProcedureName = '{0}'", name));
        Server.ExecuteNonQuery(transaction, 
          string.Format("DELETE FROM eProcedure WHERE eProcedureName = '{0}'", name));

        if (Server.SchemaVersion >= SchemaVersion.Version70)
        {
          Server.ExecuteNonQuery(transaction,
            string.Format("DELETE FROM eProcedureLibrary WHERE eProcedureName = '{0}'", name));
        }

        transaction.Commit();
      }
    }

    #endregion
  }
}
